{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Dynamically Select Tools\n",
    "Use wildcard to dynamically select the right tool to use based on the user's request."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install agentsjson\n",
    "%pip install openai"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup API keys and references to `agents.json` files\n",
    "- You need to first setup accounts and apps for the APIs you want to use.\n",
    "- You can use a service lke Postman to obtain OAuth2 tokens for APIs.\n",
    "- For Google use: https://developers.google.com/oauthplayground/"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [],
   "source": [
    "OPENAI_API_KEY=\"\"\n",
    "COLLECTION_NAME=\"\"\n",
    "\n",
    "RESEND_API_KEY=\"<your-resend-api-key>\"\n",
    "HUBSPOT_ACCESS_TOKEN=\"<your-hubspot-access-token>\"\n",
    "GOOGLE_SHEETS_ACCESS_TOKEN=\"<your-google-sheets-access-token>\"\n",
    "\n",
    "RESEND_AGENTS_JSON_URL=\"https://raw.githubusercontent.com/wild-card-ai/agents-json/refs/heads/master/agents_json/resend/agents.json\"\n",
    "HUBSPOT_AGENTS_JSON_URL=\"https://raw.githubusercontent.com/wild-card-ai/agents-json/refs/heads/lang/typescript/agents_json/hubspotcontacts/agents.json\"\n",
    "GOOGLE_SHEETS_AGENTS_JSON_URL=\"https://raw.githubusercontent.com/wild-card-ai/agents-json/refs/heads/lang/typescript/agents_json/googlesheets/agents.json\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load the `agents.json` files"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [],
   "source": [
    "from agentsjson.core.models import Flow\n",
    "from agentsjson.core.loader import load_agents_json\n",
    "import json\n",
    "\n",
    "# load the agents.json file\n",
    "resend_bundle = load_agents_json(RESEND_AGENTS_JSON_URL)\n",
    "hubspot_bundle = load_agents_json(HUBSPOT_AGENTS_JSON_URL)\n",
    "google_sheets_bundle = load_agents_json(GOOGLE_SHEETS_AGENTS_JSON_URL)\n",
    "\n",
    "# get the flows\n",
    "resend_flows = resend_bundle.agentsJson.flows\n",
    "hubspot_flows = hubspot_bundle.agentsJson.flows\n",
    "google_sheets_flows = google_sheets_bundle.agentsJson.flows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup Authentication"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "from agentsjson.core.models.auth import OAuth2AuthConfig, ApiKeyAuthConfig, AuthType\n",
    "\n",
    "# OAuth2 config for HubSpot\n",
    "hubspot_auth = OAuth2AuthConfig(\n",
    "    type=AuthType.OAUTH2,\n",
    "    token=HUBSPOT_ACCESS_TOKEN,\n",
    "    token_type=\"Bearer\",  # Adding token_type explicitly\n",
    "    refresh_token=None,\n",
    "    expires_at=None,\n",
    "    scopes=None\n",
    ")\n",
    "\n",
    "# OAuth2 config for Google Sheets\n",
    "google_sheets_auth = OAuth2AuthConfig(\n",
    "    type=AuthType.OAUTH2,\n",
    "    token=GOOGLE_SHEETS_ACCESS_TOKEN,\n",
    "    token_type=\"Bearer\",  # Adding token_type explicitly\n",
    "    refresh_token=None,\n",
    "    expires_at=None,\n",
    "    scopes=None\n",
    ")\n",
    "\n",
    "# API Key config for Resend\n",
    "resend_auth = ApiKeyAuthConfig(\n",
    "    type=AuthType.API_KEY,\n",
    "    key_value=RESEND_API_KEY,\n",
    "    key_name=None,\n",
    "    key_prefix=None\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setup your agent Toolkit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "toolkit = {\n",
    "    \"hubspot\": {\n",
    "        \"flows\": hubspot_flows,\n",
    "        \"bundle\": hubspot_bundle,\n",
    "        \"auth\": hubspot_auth\n",
    "    },\n",
    "    \"google sheets\": {\n",
    "        \"flows\": google_sheets_flows,\n",
    "        \"bundle\": google_sheets_bundle,\n",
    "        \"auth\": google_sheets_auth\n",
    "    },\n",
    "    \"resend\": {\n",
    "        \"flows\": resend_flows,\n",
    "        \"bundle\": resend_bundle,\n",
    "        \"auth\": resend_auth\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define agent creation function\n",
    "\n",
    "This is a generic implementation of an agent that can process any natural language request."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "from openai import OpenAI\n",
    "from agentsjson.core import ToolFormat, flows_tools, execute_flows\n",
    "\n",
    "def create_agent(bundle, flows, system_prompt, auth):\n",
    "    openai_client = OpenAI(api_key=OPENAI_API_KEY)\n",
    "    \n",
    "    def agent(user_request):\n",
    "        response = openai_client.chat.completions.create(\n",
    "            model=\"gpt-4o\",\n",
    "            messages=[{\"role\": \"system\", \"content\": system_prompt}, {\"role\": \"user\", \"content\": user_request}],\n",
    "            tools=flows_tools(flows, format=ToolFormat.OPENAI),\n",
    "            tool_choice=\"auto\",\n",
    "        )\n",
    "        \n",
    "        # Run the flows        \n",
    "        response = execute_flows(response, format=ToolFormat.OPENAI, bundle=bundle, flows=flows, auth=auth)\n",
    "        return response\n",
    "    return agent"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create Wildcard Agent\n",
    "Create an agent that will access the Wildcard API to find the right tool to use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [],
   "source": [
    "wildcard_system_prompt = \"\"\"You are a wildcard agent that has access to a very special set of tools that can do many things.\n",
    "Whenever you are given a request analyze whether you need a tool call to accomplish the task or not.\n",
    "Make a separate request for each unique API you need to call.\n",
    "If you need a tool call call the wildcard_tool with information about the task to search for the right tool to use.\n",
    "\n",
    "You must give your arguments for the tool call as Structued Outputs JSON\"\"\"\n",
    "\n",
    "\n",
    "wildcard_tool = {\n",
    "    \"type\": \"function\",\n",
    "    \"function\": {\n",
    "        \"name\": \"wildcard_tool\",\n",
    "        \"description\": \"This function is responsible for calling the wildcard tool search API to find the right tool to use.\",\n",
    "        \"parameters\": {\n",
    "            \"type\": \"object\",\n",
    "            \"properties\": {\n",
    "                \"task\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"A brief description of the task to accomplish described precisely in natural language. Include API name if available. For example: 'Create a new contact in HubSpot'\"\n",
    "                }\n",
    "            },\n",
    "            \"required\": [\"task\"],\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Submit your Query"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [],
   "source": [
    "query = \"Get google sheet data for the sheet called My Customer Info\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Find the Right Tool to Use with Wildcard Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from openai import OpenAI\n",
    "from agentsjson.core import execute\n",
    "\n",
    "openai_client = OpenAI(api_key=OPENAI_API_KEY)\n",
    "\n",
    "messages = [{\"role\": \"system\", \"content\": wildcard_system_prompt}, {\"role\": \"user\", \"content\": query}]\n",
    "\n",
    "response = openai_client.chat.completions.create(\n",
    "    model=\"gpt-4o\",  # Fixed model name\n",
    "    messages=messages,\n",
    "    tools=[wildcard_tool],\n",
    "    tool_choice=\"auto\",\n",
    "    parallel_tool_calls=False\n",
    ")\n",
    "\n",
    "print(\"\\nRESPONSE FROM WILDCARD AGENT:\")\n",
    "print(json.dumps(response.model_dump(), indent=2))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Call the Wildcard Tool Selection API"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "WILDCARD_API_KEY = \"<your-wildcard-api-key>\"\n",
    "\n",
    "tool_call = response.choices[0].message.tool_calls[0]\n",
    "\n",
    "if tool_call.function.name != \"wildcard_tool\":\n",
    "    raise ValueError(\"Tool call is not a wildcard tool call\")\n",
    "\n",
    "# Parse the arguments from the tool call\n",
    "args = json.loads(tool_call.function.arguments)\n",
    "task = args[\"task\"]\n",
    "\n",
    "search_url = \"https://queryfd.onrender.com/search\"\n",
    "search_params = {\n",
    "    \"query\": task,\n",
    "    \"collection_name\": COLLECTION_NAME\n",
    "}\n",
    "\n",
    "search_response = requests.get(search_url, params=search_params, headers={\"x-api-key\": WILDCARD_API_KEY})\n",
    "search_response.raise_for_status()\n",
    "search_results = search_response.json()\n",
    "\n",
    "print(json.dumps(search_results, indent=2))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_id = search_results[\"points\"][0][\"payload\"][\"flow\"][\"id\"]\n",
    "api_name = search_results[\"points\"][0][\"payload\"][\"info\"][\"title\"]\n",
    "\n",
    "# Clean and match API name to toolkit keys\n",
    "api_name = next((key for key in toolkit.keys() if key in api_name.lower()), None)\n",
    "flow = next((f for f in toolkit[api_name][\"flows\"] if f.id == flow_id), None)\n",
    "\n",
    "print(\"Flow ID:\", flow_id)\n",
    "print(\"API Name:\", api_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Execute the Selected Flow"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create an agent to handle the original task using the selected flow\n",
    "agent = create_agent(\n",
    "    bundle=toolkit[api_name][\"bundle\"],\n",
    "    flows=[flow], # Use just the selected flow\n",
    "    system_prompt=f\"You are an AI assistant that helps users with {api_name} tasks.\",\n",
    "    auth=toolkit[api_name][\"auth\"]\n",
    ")\n",
    "\n",
    "# Execute the original task using the agent\n",
    "agent_response = agent(query)\n",
    "print(f\"\\nAgent response for {api_name} task:\")\n",
    "print(json.dumps(agent_response, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Save the response to the message history and continue the conversation\n",
    "- You can save the response to the message history and continue the conversation history to make a subsequent request to the agent.\n",
    "- We suggest include a reflection step to see if there are any follow up questions or tasks to complete."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "newenv2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
